# @Time    : 2022/10/13 19:55
# @Author  : 南黎
# @FileName: 2.采用不同的距离算法.py
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
from  sklearn.cluster import AgglomerativeClustering
#读取数据
DFdata=pd.read_csv("testSet.csv")
data=DFdata.values#dataframe数据类型转为列表

#设置 matplotlib rc配置文件
matplotlib.rcParams['font.sans-serif'] = [u'SimHei'] # 用来设置字体样式以正常显示中文标签
matplotlib.rcParams['axes.unicode_minus'] = False # 设置为 Fasle 来解决负号的乱码问题

#affinity 距离算法参数
#name 距离算法名字
def myTest(affinity,name):
    k = 4  # 假设聚类为 4 类.
    k = 8  #4个距离的模型在分为4类时的效果训练可视化效果居然完全一致·······数据量还是太小，区别不出不同距离方法的区别，所以我后来就改为了分为8类，看到了不同距离方法的效果。
    # 构建算法模型
    km = AgglomerativeClustering(affinity=affinity,compute_full_tree="auto",n_clusters=k,linkage="average")

    #- affinity ，默认：“欧几里得”用于计算链接的度量。可以是“euclidean”, “l1”, “l2”, “manhattan”, “cosine”, or ‘precomputed’
    #样本点之间距离计算方式，可以是euclidean(欧式距离), l1、 l2、manhattan(曼哈顿距离)、cosine(余弦距离)、precomputed(可以预先设定好距离)，如果参数linkage选择“ward”的时候只能使用euclidean。
    #- compute_full_tree bool 或 'auto' (可选)在 n_clusters 处尽早停止树的构建。如果集群的数量与样本数量相比不小，这对于减少计算时间很有用。此选项仅在指定连接矩阵时有用。还要注意，当改变集群的数量并使用缓存时，计算完整的树可能是有利的。
    #- n_clusters 参数表示分成几个簇整数，默认=2要查找的集群数。
    #- linkage : {“ward”, “complete”, “average”}，可选，默认：“ward” 会导致 affinity只能是euclidean
      #使用哪个链接标准。链接标准确定在观察集之间使用哪个距离。该算法将合并使该标准最小化的集群对。
      #- ward 最小化被合并的集群的方差。
      #- average 平均值使用两组每个观测值的距离平均值。
      #- complete完整或最大链接使用两组所有观测值之间的最大距离。
    km.fit(data)

    # 获取聚类后样本所属簇的对应编号（label_pred）
    label_pred = km.labels_  # labels_属性表示每个点的分簇号，会得到一个关于簇编号的数组

    # 未聚类前的数据分布图
    plt.subplot(121)
    plt.scatter(data[:, 0], data[:, 1], s=50)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title("未聚类之前")
    # wspace 两个子图之间保留的空间宽度
    plt.subplots_adjust(wspace=0.5) # subplots_adjust（）用于调整边距和子图间距
    # 聚类后的分布图
    plt.subplot(122)
    # c：表示颜色和色彩序列，此处与 cmap 颜色映射一起使用（cool是颜色映射值）s表示散点的的大小，marker表示标记样式（散点样式）
    plt.scatter(data[:, 0], data[:, 1], c=label_pred, s=50, cmap='cool')

    plt.xlabel('x')
    plt.ylabel('y')
    plt.title("2.距离算法"+name)
    plt.savefig("2/2.距离算法"+name+".png")
    plt.show()
myTest("euclidean","欧式距离")
myTest("manhattan","曼哈顿距离")

#切比雪夫距离 没有内置的···用l1代替
myTest("l1","l1")

myTest("cosine","余弦距离")